package com.culturalCenter.dataCenter.schedule.user;

import cn.hutool.core.date.DateUtil;
import com.culturalCenter.dataCenter.Utils.RedisUtil;
import com.culturalCenter.dataCenter.entity.user.*;
import com.culturalCenter.dataCenter.mapper.user.*;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 定时任务_用户_统计
 *
 * @author 方治森
 * @since 2022/4/20
 */
@Component
@Slf4j
@Async("dataThreadExecutor")
public class UserDataStatistics {

    @Resource
    private UserMapper userMapper;
    @Resource
    private UserFootprintMapper userFootprintMapper;
    @Resource
    private UserFootrpintCountMapper userFootrpintCountMapper;
    @Resource
    private UserActivityMapper userActivityMapper;
    @Resource
    private UserAgeCountMapper userAgeCountMapper;
    @Resource
    private UserDayNumberMapper userDayNumberMapper;
    @Resource
    private UserTypeCountMapper userTypeCountMapper;
    @Resource
    private UserInfoCountMapper userInfoCountMapper;
    @Resource
    private UserZodiacChinaMapper userZodiacChinaMapper;
    @Resource
    private UserZodiacForeignMapper userZodiacForeignMapper;
    @Resource
    private UserActivitySignUpTypeMapper userActivitySignUpTypeMapper;
    @Resource
    private UserActivitySignUpContentTypeMapper userActivitySignUpContentTypeMapper;
    @Resource
    private UserActivityCountMapper userActivityCountMapper;
    @Resource
    private UserActivityLogMapper userActivityLogMapper;
    @Resource
    private UserLocationMapper userLocationMapper;
    @Resource
    private UserLocationTypeCountMapper userLocationTypeCountMapper;
    @Resource
    private UserLocationCountMapper userLocationCountMapper;
    @Resource
    private UserLocationPictureMapper userLocationPictureMapper;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RedissonClient redisson;
    private long user_statistics_timestamp1;
    private long user_statistics_timestamp2;
    private long user_statistics_timestamp3;
    private long user_statistics_timestamp4;
    private final int size = 1000;

    /**
     * 初始化
     */
    @PostConstruct
    public void initLock() {
        user_statistics_timestamp1 = !redisUtil.redisTemplate.hasKey("user_statistics_timestamp1") ? 0 : Long.parseLong(redisUtil.get("user_statistics_timestamp1"));
        user_statistics_timestamp2 = !redisUtil.redisTemplate.hasKey("user_statistics_timestamp2") ? 0 : Long.parseLong(redisUtil.get("user_statistics_timestamp2"));
        user_statistics_timestamp3 = !redisUtil.redisTemplate.hasKey("user_statistics_timestamp3") ? 0 : Long.parseLong(redisUtil.get("user_statistics_timestamp3"));
        user_statistics_timestamp4 = !redisUtil.redisTemplate.hasKey("user_statistics_timestamp4") ? 0 : Long.parseLong(redisUtil.get("user_statistics_timestamp4"));

        // for test
        // for (int i = 1; i <= 4; i++) {
        //     redisUtil.del("userStatistics_lock" + i);
        // }
    }

    /**
     * 用户(cdc_user_day_number、cdc_user_age_count、cdc_user_type_count、cdc_user_info_count、cdc_user_zodiac_china、cdc_user_zodiac_foreign)
     */
//    @Scheduled(cron = "${cron.userStatistics}")
    // @Scheduled(cron = "${cron.test}")
    public void countUser() {
        String lockKey = "userStatistics_lock1";
        RLock redissonLock = redisson.getLock(lockKey);
        try {
            boolean locked = redissonLock.isLocked();
            if (!locked){
                redissonLock.lock();
            }
            log.info("============用户信息统计表开始统计===========");

            // 新增用户
            List<UserDayNumber> userDayNumberList = new ArrayList<>();
            for (Date date = DateUtil.beginOfMonth(DateUtil.beginOfDay(new Date())); date.before(DateUtil.beginOfDay(DateUtil.tomorrow())); date = DateUtil.offsetDay(date, 1)) {
                UserDayNumber userDayNumber = userMapper.countByDay(date);
                userDayNumberList.add(userDayNumber);
            }
            userDayNumberMapper.insertBatch(userDayNumberList);
            // 用户年龄
            userAgeCountMapper.deleteAll();
            UserAgeCount userAgeCount = new UserAgeCount();
            for (int i = 1; i < 10; i++) {
                int startAge = 10 * i;
                int endAge = startAge + 9;
                userAgeCount.setStartAge(startAge);
                userAgeCount.setEndAge(endAge);
                userAgeCount.setNum(userMapper.countByAge(startAge, endAge));
                userAgeCount.setUpdateTime(new Date());
                userAgeCountMapper.insertSelective(userAgeCount);
            }
            // 用户类型
            userTypeCountMapper.deleteAll();
            userTypeCountMapper.insert(userMapper.countUserType());
            // 用户信息
            // activityNum、trainNum
            List<UserInfoCount> userInfoCountList = userActivityMapper.countActivityAndTrainNum();
            batchInsertion(userInfoCountList);
            // visitWebTime
            userInfoCountList = userFootprintMapper.selectRecentFootprint();
            batchInsertion(userInfoCountList);
            // joinActivityTime、visitSiteTime
            userInfoCountList = userActivityMapper.selectRecentActivity();
            batchInsertion(userInfoCountList);
            // 生肖和星座
            userZodiacChinaMapper.deleteAll();
            userZodiacForeignMapper.deleteAll();
            userZodiacChinaMapper.insert(userMapper.countByZodiacChina());
            userZodiacForeignMapper.insert(userMapper.countByZodiacForeign());

            log.info("============用户信息统计表统计完毕===========");
        } finally {
            boolean locked = redissonLock.isLocked();
            if (locked){
                redissonLock.unlock();
            }
        }
    }

    private void batchInsertion(List<UserInfoCount> userInfoCountList) {
        if (CollectionUtils.isNotEmpty(userInfoCountList)) {
            int number = userInfoCountList.size();
            int page = number % size == 0 ? number / size : number / size + 1;
            for (int num = 0; num < page; num++) {
                userInfoCountMapper.insertBatch(userInfoCountList.stream().skip(num * size).limit(size).collect(Collectors.toList()));
            }
        }
    }

    /**
     * 用户活动(cdc_user_activity_signUpType、cdc_user_activity_signUpContentType、cdc_user_activity_count、cdc_user_activity_log)
     */
//    @Scheduled(cron = "${cron.userStatistics}")
    // @Scheduled(cron = "${cron.test}")
    public void countUserActivity() {
        String lockKey = "userStatistics_lock2";
        RLock redissonLock = redisson.getLock(lockKey);
        try {
            boolean locked = redissonLock.isLocked();
            if (!locked){
                redissonLock.lock();
            }
            // 报名类别统计
            List<UserActivitySignUpType> userActivitySignUpTypeList = userActivityMapper.countByActivityType();
            if (CollectionUtils.isNotEmpty(userActivitySignUpTypeList)) {
                int page = userActivitySignUpTypeList.size() % size == 0 ? userActivitySignUpTypeList.size() / size : userActivitySignUpTypeList.size() / size + 1;
                for (int num = 0; num < page; num++) {
                    userActivitySignUpTypeMapper.insertBatch(userActivitySignUpTypeList.stream().skip(num * size).limit(size).collect(Collectors.toList()));
                }
            }
            // 报名内容类别统计
            List<UserActivitySignUpContentType> userActivitySignUpContentTypeList = userActivityMapper.countByContentType();
            if (CollectionUtils.isNotEmpty(userActivitySignUpContentTypeList)) {
                int page = userActivitySignUpContentTypeList.size() % size == 0 ? userActivitySignUpContentTypeList.size() / size : userActivitySignUpContentTypeList.size() / size + 1;
                for (int num = 0; num < page; num++) {
                    userActivitySignUpContentTypeMapper.insertBatch(userActivitySignUpContentTypeList.stream().skip(num * size).limit(size).collect(Collectors.toList()));
                }
            }
            // 用户参与统计
            List<UserActivityCount> userActivityCountList = userActivityMapper.countActivityNum();
            if (CollectionUtils.isNotEmpty(userActivityCountList)) {
                int page = userActivityCountList.size() % size == 0 ? userActivityCountList.size() / size : userActivityCountList.size() / size + 1;
                for (int num = 0; num < page; num++) {
                    userActivityCountMapper.insertBatch(userActivityCountList.stream().skip(num * size).limit(size).collect(Collectors.toList()));
                }
            }

            // 活动开始、结束报名
            List<UserActivityLog> activityRegisterTimeList = userActivityMapper.selectActivityRegisterTime(user_statistics_timestamp1);
            insertBatch(activityRegisterTimeList);
            // 培训开始、结束报名
            List<UserActivityLog> trainRegisterTimeList = userActivityMapper.selectTrainRegisterTime(user_statistics_timestamp1);
            insertBatch(trainRegisterTimeList);
            // 活动场次开始、结束签到
            List<UserActivityLog> activitySignInTimeList = userActivityMapper.selectActivitySignInTime(user_statistics_timestamp1);
            insertBatch(activitySignInTimeList);
            // 活动场次开始、结束
            List<UserActivityLog> activityTimeList = userActivityMapper.selectActivityTime(user_statistics_timestamp1);
            insertBatch(activityTimeList);
            // 培训场次开始、结束
            List<UserActivityLog> trainingTimeList = userActivityMapper.selectTrainingTime(user_statistics_timestamp1);
            insertBatch(trainingTimeList);
            // 用户查看
            List<UserActivityLog> browsingTimeList = userActivityMapper.selectBrowsingTime(user_statistics_timestamp1);
            insertBatch(browsingTimeList);
            // 用户报名、签到
            List<UserActivityLog> registerTimeList = userActivityMapper.selectRegisterTime(user_statistics_timestamp1);
            insertBatch(registerTimeList);

            redisUtil.set("user_statistics_timestamp1", String.valueOf(System.currentTimeMillis()));
            log.info("============用户活动表统计完毕===========");
        } finally {
            boolean locked = redissonLock.isLocked();
            if (locked){
                redissonLock.unlock();
            }        }
    }

    private void insertBatch(List<UserActivityLog> dataList) {
        if (CollectionUtils.isNotEmpty(dataList)) {
            int number = dataList.size();
            int page = number % size == 0 ? number / size : number / size + 1;
            for (int num = 0; num < page; num++) {
                userActivityLogMapper.insertBatch(dataList.stream().skip(num * size).limit(size).collect(Collectors.toList()));
            }
        }
    }

    /**
     * 用户现场记录(cdc_user_location、cdc_user_location_type_count、cdc_user_location_count)
     */
//    @Scheduled(cron = "${cron.userStatistics}")
//     @Scheduled(cron = "${cron.test}")
    public void countUserLocation() {
        String lockKey = "userStatistics_lock3";

        RLock redissonLock = redisson.getLock(lockKey);
        try {
            boolean locked = redissonLock.isLocked();
            if (!locked){
                redissonLock.lock();
            }
            log.info("============用户现场记录表开始统计===========");

            // 用户活动定位记录
            List<UserLocation> userLocationList = userActivityMapper.selectActivityLocation(user_statistics_timestamp2);
            List<UserLocation> list;
            if (CollectionUtils.isNotEmpty(userLocationList)) {
                int size=userLocationList.size();
                for (int i=0;i<userLocationList.size();i=i+1000){
                    if (size<1000){
                        list = userLocationList.subList(i, i+size);
                        userLocationMapper.insertBatch(list);
                    }else {
                        list = userLocationList.subList(i, i + 1000);
                        userLocationMapper.insertBatch(list);
                    }
                    size=size-1000;
                }
                redisUtil.set("user_statistics_timestamp2", String.valueOf(userLocationList.stream().max(Comparator.comparing(UserLocation::getUpdateTime)).get().getUpdateTime().getTime()));
            }
            // 用户培训定位记录
            userLocationList = userActivityMapper.selectTrainLocation(user_statistics_timestamp3);
            if (CollectionUtils.isNotEmpty(userLocationList)) {
                int size=userLocationList.size();
                for (int i=0;i<userLocationList.size();i=i+100) {
                    if (size < 100) {
                        list = userLocationList.subList(i, i + size);
                        userLocationMapper.insertBatch(list);
                    } else {
                        list = userLocationList.subList(i, i + 100);
                        userLocationMapper.insertBatch(list);
                    }
                    size = size - 100;
                }
                redisUtil.set("user_statistics_timestamp3", String.valueOf(userLocationList.stream().max(Comparator.comparing(UserLocation::getUpdateTime)).get().getUpdateTime().getTime()));
            }
            // 用户摄像头截图定位记录（无关活动/培训）
            userLocationList = userLocationPictureMapper.selectUserLocation(user_statistics_timestamp4);
            if (CollectionUtils.isNotEmpty(userLocationList)) {
                userLocationMapper.insertBatch(userLocationList);
                redisUtil.set("user_statistics_timestamp4", String.valueOf(userLocationList.stream().max(Comparator.comparing(UserLocation::getUpdateTime)).get().getUpdateTime().getTime()));
            }
            // 统计定位类型
            List<UserLocationTypeCount> userLocationTypeCountList = userLocationMapper.countLocationType();
            if (CollectionUtils.isNotEmpty(userLocationTypeCountList)) {
                userLocationTypeCountMapper.insertBatch(userLocationTypeCountList);
            }
            // 根据位置统计数量
            List<UserLocationCount> userLocationCountList = userLocationMapper.countLocation();
            if (CollectionUtils.isNotEmpty(userLocationCountList)) {
                userLocationCountMapper.insertBatch(userLocationCountList);
            }

            log.info("============用户现场记录表统计完毕===========");
        } finally {
            boolean locked = redissonLock.isLocked();
            if (locked){
                redissonLock.unlock();
            }
        }
    }

    /**
     * 用户浏览记录(cdc_user_footprint_count)
     */
//    @Scheduled(cron = "${cron.userStatistics}")
    // @Scheduled(cron = "${cron.test}")
    public void countUserFootprintCount() {
        String lockKey = "userStatistics_lock4";
        RLock redissonLock = redisson.getLock(lockKey);
        try {
            redissonLock.lock();
            List<UserFootrpintCount> userFootprintCountList = userFootprintMapper.countUserFootprint();
            if (CollectionUtils.isNotEmpty(userFootprintCountList)) {
                userFootrpintCountMapper.insertBatch(userFootprintCountList);
            }

            log.info("============用户浏览记录表统计完毕===========");
        } finally {
            boolean locked = redissonLock.isLocked();
            if (locked){
                redissonLock.unlock();
            }
        }
    }

}
